﻿using System;
using System.Collections.Generic;
using GGameFramework;
using GGameFramework.Core.Pool;
using UnityEngine;

namespace GGFramework.Core.Timer
{
    [DisallowMultipleComponent]
    public class TimerManager : FrameworkModule
    {
        internal override int Priority => (int)FrameworkSystemPriority.Timer;

        private readonly Dictionary<int, TimerBase> _activeTimers = new();
        private readonly List<TimerBase> _timersToAdd = new();
        private readonly List<int> _timersToRemove = new();
        private int _idCounter = 1;

        private IReferencePool<FrameTimer> _frameTimerPool;
        private IReferencePool<LoopTimer> _loopTimerPool;
        private IReferencePool<CountdownTimer> _countdownTimerPool;

        public TimerManager()
        {
            _frameTimerPool = new FixedReferencePool<FrameTimer>(() => new FrameTimer(), null, null, null, 100);
            _loopTimerPool = new FixedReferencePool<LoopTimer>(() => new LoopTimer(), null, null, null, 100);
            _countdownTimerPool = new FixedReferencePool<CountdownTimer>(() => new CountdownTimer(), null, null, null, 100);
        }

        #region 公共方法

        /// <summary>
        /// 创建倒计时
        /// </summary>
        /// <param name="duration"></param>
        /// <param name="onComplete"></param>
        /// <param name="ignoreTimeScale"></param>
        /// <returns></returns>
        public CountdownTimer CreateTimer(float duration, Action onComplete,
            bool ignoreTimeScale = false)
        {
            var timer = _countdownTimerPool.Spawn();
            timer.Init(duration);
            timer.Callback = onComplete;
            timer.IgnoreTimeScale = ignoreTimeScale;
            timer.ID = _idCounter++;
            RegisterTimer(timer);
            return timer;
        }

        /// <summary>
        /// 创建循环计时器
        /// </summary>
        /// <param name="interval"> 间隔时间 </param>
        /// <param name="onLoop"> 循环回调 </param>
        /// <param name="loops"> 循环次数 </param>
        /// <param name="ignoreTimeScale"> 是否忽略时间缩放 </param>
        /// <returns></returns>
        public LoopTimer CreateLoopTimer(float interval, Action onLoop,
            int loops = -1, bool ignoreTimeScale = false)
        {
            var timer = _loopTimerPool.Spawn();
            timer.Init(interval, loops);
            timer.Callback = onLoop;
            timer.IgnoreTimeScale = ignoreTimeScale;
            timer.ID = _idCounter++;
            RegisterTimer(timer);
            return timer;
        }


        /// <summary>
        /// 创建帧计时器
        /// </summary>
        /// <param name="frames"> 帧数 </param>
        /// <param name="onComplete"> 完成回调 </param>
        /// <param name="onUpdate"> 更新回调 </param>
        public FrameTimer CreateFrameTimer(int frameCount, Action onComplete,
            Action<int> onUpdate = null)
        {
            var timer = _frameTimerPool.Spawn();
            timer.Init(frameCount);
            timer.Callback = onComplete;
            timer.UpdateCallback = onUpdate;
            timer.ID = _idCounter++;
            RegisterTimer(timer);
            return timer;
        }

        /// <summary>
        /// 取消计时器
        /// </summary>
        /// <param name="timerId"> 计时器ID </param>
        public void CancelTimer(int timerId)
        {
            if (_activeTimers.TryGetValue(timerId, out var timer))
            {
                timer.Cancel();
            }
        }

        /// <summary>
        /// 暂停计时器
        /// </summary>
        /// <param name="timerId"> 计时器ID </param>
        public void PauseTimer(int timerId)
        {
            if (_activeTimers.TryGetValue(timerId, out var timer))
            {
                timer.Pause();
            }
        }

        /// <summary>
        /// 恢复计时器
        /// </summary>
        /// <param name="timerId"> 计时器ID </param>
        public void ResumeTimer(int timerId)
        {
            if (_activeTimers.TryGetValue(timerId, out var timer))
            {
                timer.Resume();
            }
        }

        /// <summary>
        /// 暂停所有计时器
        /// </summary>
        public void PauseAll()
        {
            foreach (var timer in _activeTimers.Values)
            {
                timer.Pause();
            }
        }

        /// <summary>
        /// 恢复所有计时器
        /// </summary>
        public void ResumeAll()
        {
            foreach (var timer in _activeTimers.Values)
            {
                timer.Resume();
            }
        }

        /// <summary>
        /// 清空所有计时器
        /// </summary>
        public void ClearAll()
        {
            foreach (var timer in _activeTimers.Values)
            {
                if (timer is TimerBase tb) ReturnTimer(tb);
            }

            _activeTimers.Clear();
        }

        #endregion

        #region FrameworkModule实现
        
        internal override void Update(float elapseSeconds, float realElapseSeconds)
        {
            // 添加新计时器
            if (_timersToAdd.Count > 0)
            {
                foreach (var timer in _timersToAdd)
                {
                    _activeTimers[timer.ID] = timer;
                }

                _timersToAdd.Clear();
            }

            // 清空待移除列表
            _timersToRemove.Clear();

            // 更新所有计时器
            foreach (var pair in _activeTimers)
            {
                var timer = pair.Value;

                float dt = timer.IgnoreTimeScale ? realElapseSeconds : elapseSeconds;
                timer.Update(dt);

                // 检查是否完成
                if (timer.IsExpired || timer.IsCompleted)
                {
                    _timersToRemove.Add(pair.Key);
                }
            }

            // 移除完成的计时器
            if (_timersToRemove.Count > 0)
            {
                foreach (int id in _timersToRemove)
                {
                    if (_activeTimers.TryGetValue(id, out var timer))
                    {
                        ReturnTimer(timer);
                        _activeTimers.Remove(id);
                    }
                }
            }
        }

        internal override void Shutdown()
        {
            ClearAll();
        }

        #endregion

        #region 内部方法

        private void ReturnTimer(TimerBase timer)
        {
            if (timer is FrameTimer frameTimer)
                _frameTimerPool.Recycle(frameTimer);
            else if (timer is LoopTimer loopTimer)
                _loopTimerPool.Recycle(loopTimer);
            else if (timer is CountdownTimer countdownTimer)
                _countdownTimerPool.Recycle(countdownTimer);
        }

        private void RegisterTimer(TimerBase timer)
        {
            _timersToAdd.Add(timer);
        }

        #endregion
    }
}